﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Tesla.Content.Loaders;
using Tesla.Content;
using Tesla.Graphics;

namespace TeslaEffectCompiler {
    /// <summary>
    /// Tesla Effect Compiler
    /// </summary>
    public partial class CompilerForm : Form {

        /// <summary>
        /// Creates a new instance of <see cref="CompilerForm"/>.
        /// </summary>
        public CompilerForm() {
            InitializeComponent();
            InitData();
            base.FormClosing += new FormClosingEventHandler(SavePaths);
        }

        private void InitData() {
            //Get the file path to look for effect files
            Properties.config config = TeslaEffectCompiler.Properties.config.Default;
            String filePath = config.FilePath;
            if(String.IsNullOrEmpty(filePath) || !Directory.Exists(filePath)) {
                //If first time startup, use title path
                filePath = ResourceUtils.TitlePath;
            }
            filePathTextBox.Text = filePath;
            filePathBrowser.SelectedPath = filePathTextBox.Text;

            //Get the file path that will be where we output tebo files
            String outputPath = config.OutputPath;
            if(String.IsNullOrEmpty(outputPath) || !Directory.Exists(filePath)) {
                //If first time startup, use the title path
                outputPath = ResourceUtils.TitlePath;
            }
            outputPathTextBox.Text = outputPath;

            outputPathBrowser.SelectedPath = outputPathTextBox.Text;

            //Check to see if there's any valid files and list them
            ListEffectFiles(filePathTextBox.Text);
        }

        private void SavePaths(Object sender, FormClosingEventArgs args) {
            //Save user defined paths for future use.
            if(args.CloseReason == CloseReason.ApplicationExitCall) {
                Properties.config config = TeslaEffectCompiler.Properties.config.Default;
                config.FilePath = filePathTextBox.Text;
                config.OutputPath = outputPathTextBox.Text;
                config.Save();
            }
        }

        private void ListEffectFiles(String filePath) {
            effectFilesListBox.Items.Clear();
            //Right now only scan FX files...need to expand this later
            String pattern = "*.fx";
            //if(((Platform) platformSelection.SelectedIndex) == Platform.OpenGL) {
            //    pattern = "*.cgfx";
            //}
            if(!Directory.Exists(filePath)) {
                return;
            }
            IEnumerable<String> files = Directory.EnumerateFiles(filePath, pattern);
            foreach(String file in files) {
                String name = Path.GetFileName(file);
                int index = effectFilesListBox.Items.Add(name);
                effectFilesListBox.SetItemCheckState(index, CheckState.Checked);
            }
        }

        private void QuitExit(object sender, MouseEventArgs e) {
            Application.Exit();
        }

        private void ShowFilePathBrowser(object sender, MouseEventArgs e) {
            System.Windows.Forms.DialogResult result = filePathBrowser.ShowDialog();

            if(result == System.Windows.Forms.DialogResult.OK) {
                filePathTextBox.Text = filePathBrowser.SelectedPath;
                ListEffectFiles(filePathTextBox.Text);
            }
       }

        private void ShowOutputPathBrowser(object sender, MouseEventArgs e) {
            System.Windows.Forms.DialogResult result = outputPathBrowser.ShowDialog();

            if(result == System.Windows.Forms.DialogResult.OK) {
                outputPathTextBox.Text = outputPathBrowser.SelectedPath;
            }
        }

        private IEffectCompiler CreatePlatformCompiler(Platform platform) {
            switch(platform) {
                case Platform.Direct3D10:
                    return new D3D10EffectCompiler(filePathTextBox.Text);
                case Platform.XNA4Windows:
                    return new XNAEffectCompiler(filePathTextBox.Text);
                case Platform.XNA4Xbox:
                    return new XNAEffectCompiler(filePathTextBox.Text, Microsoft.Xna.Framework.Content.Pipeline.TargetPlatform.Xbox360);
                default:
                    throw new InvalidOperationException("Invalid platform selected.");
            }
        }

        private bool AskOverwrite(String file) {
            if(File.Exists(file)) {
                String name = Path.GetFileName(file);
                
                DialogResult result = MessageBox.Show(String.Format("File {0} exists, overwrite?", name), "Overwrite file?", MessageBoxButtons.OKCancel);
                if(result != System.Windows.Forms.DialogResult.OK) {
                    return false;
                }
            }
            return true;
        }

        private void CompileEffectFiles(object sender, MouseEventArgs e) {
            Platform platform = (Platform) platformSelection.SelectedIndex;
            String filePath = filePathTextBox.Text;
            String outputPath = outputPathTextBox.Text;

            if(String.IsNullOrEmpty(filePath) || !Directory.Exists(filePath)) {
                MessageBox.Show("Please select a valid file path.");
                return;
            }

            if(String.IsNullOrEmpty(filePath) || !Directory.Exists(outputPath)) {
                MessageBox.Show("Please select a valid output file path.");
                return;
            }

            int count = effectFilesListBox.CheckedItems.Count;

            if(count == 0) {
                progressLabel.Text = "No Files selected.";
                return;
            }

            //Get the file names
            List<String> files = new List<String>();

            bool overwriteAll = overwriteCheck.Checked;
            for(int i = 0; i < count; i++) {
                String file = effectFilesListBox.CheckedItems[i] as String;
                if(overwriteAll) {
                    files.Add(file);
                } else if(AskOverwrite(Path.Combine(outputPath, file))) {
                    files.Add(file);
                }
            }

            if(files.Count == 0) {
                progressLabel.Text = "Compilation aborted.";
                return;
            }

            //Setup compiler
            IEffectCompiler compiler = CreatePlatformCompiler(platform);
            compiler.Init();

            compileProgressBar.Maximum = count * 2;

            //Compile each effect.
            int count2 = 0;
            Effect[] effects;
            try {
                effects = compiler.Compile(files.ToArray(), delegate() {
                    compileProgressBar.PerformStep();
                    count2++;
                    progressLabel.Text = String.Format("Compiling file %d of %d", count2, count);
                });
            } catch(Exception ce) {
                compiler.Dispose();
                compileProgressBar.Value = 0;
                progressLabel.Text = "Error compiling files.";
                MessageBox.Show(ce.Message, "Error", MessageBoxButtons.OK);
                return;
            }

            //Save via the binary exporter.
            try {
                BinaryExporter exporter = new BinaryExporter();
                count2 = 0;
                foreach(Effect effect in effects) {
                    FileStream fs = File.Create(Path.Combine(outputPath, effect.Name + ".tebo"));
                    exporter.Save(effect, fs);
                    fs.Flush();
                    fs.Close();
                    compileProgressBar.PerformStep();
                    count2++;
                    progressLabel.Text = String.Format("Saving file %d of %d", count2, count);
                }
            } catch(Exception ee) {
                compiler.Dispose();
                compileProgressBar.Value = 0;
                progressLabel.Text = "Error saving files.";
                MessageBox.Show(ee.Message, "Error", MessageBoxButtons.OK);
                return;
            }

            //Cleanup
            compiler.Dispose();
            compileProgressBar.Value = 0;
            progressLabel.Text = "Compilation finished, waiting...";
        }

        private void PlatformChanged(object sender, EventArgs e) {
            ListEffectFiles(filePathTextBox.Text);
        }

        private void SelectAll(object sender, MouseEventArgs e) {
            for(int i = 0; i < effectFilesListBox.Items.Count; i++) {
                effectFilesListBox.SetItemCheckState(i, CheckState.Checked);
            }
        }

        private void DeselectAll(object sender, MouseEventArgs e) {
            for(int i = 0; i < effectFilesListBox.Items.Count; i++) {
                effectFilesListBox.SetItemCheckState(i, CheckState.Unchecked);
            }
        }

        private void ShowAbout(object sender, EventArgs e) {
            MessageBox.Show("Tesla Engine Effect Compiler Tool \n\n Version: 1.0 \n\n Copyright 2011 Nicholas Woodfield", "About", MessageBoxButtons.OK);
        }

    }
}
